/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.model.command;

import static com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil.createUniqueName;

import java.util.ArrayList;
import java.util.Collection;

import org.eclipse.uml2.uml.ExecutionEvent;
import org.eclipse.uml2.uml.ExecutionOccurrenceSpecification;
import org.eclipse.uml2.uml.ExecutionSpecification;
import org.eclipse.uml2.uml.Interaction;
import org.eclipse.uml2.uml.InteractionFragment;
import org.eclipse.uml2.uml.Lifeline;
import org.eclipse.uml2.uml.StateInvariant;
import org.eclipse.uml2.uml.UMLFactory;

import com.cea.papyrus.core.utils.Debug;

/**
 * Abstract class that contains common behavior used in :
 * - {@link CreateBehaviorExecutionSpecificationCommand}
 * - {@link CreateActionExecutionSpecificationCommand}
 *
 */
public abstract class CreateExecutionSpecificationCommand extends
		AbstractNamespaceCommand {

	protected ExecutionSpecification executionSpecification;
	protected ExecutionOccurrenceSpecification startEOS;
	protected ExecutionOccurrenceSpecification finishEOS;
	protected ExecutionEvent startEvent;
	protected ExecutionEvent finishEvent;	
	protected Lifeline coveredLifeline;

	public ExecutionSpecification getExecutionSpecification() {
		return executionSpecification;
	}
	
	/**
	 * This method should not be used...
	 * use CreateBehaviorExecutionSpecificationCommand(
	 * 				Lifeline coveredLifeline, 
	 * 				InteractionFragment namespace)
	 * 
	 * instead
	 */
	public CreateExecutionSpecificationCommand() {
		super();
		Debug.log(new Exception("This method should not be used."));
	}
	
	/**
	 * Main constructor
	 * @param coveredLifeline the {@link Lifeline} covered by the new {@link StateInvariant}
	 * @param namespace the {@link Interaction} where the {@link StateInvariant} is created
	 */
	public CreateExecutionSpecificationCommand(Lifeline coveredLifeline, InteractionFragment namespace) {
		super();
		this.coveredLifeline = coveredLifeline;
		setNamespace(namespace);
	}

	@Override
	public void execute() {
		
		// Create BehaviorExecutionSpecification
		executionSpecification = CreateExecutionSpecificationElement();
		executionSpecification.setName(
				createUniqueName(getNamespaceFragments(), "ExecSpec_"));

		// Create Start ExecutionOccurenceSpecification
		startEOS = UMLFactory.eINSTANCE.createExecutionOccurrenceSpecification();
		startEOS.setName(
				createUniqueName(getNamespaceFragments(), "StartEO_"));

		// Create Stop ExecutionOccurenceSpecification
		finishEOS = UMLFactory.eINSTANCE.createExecutionOccurrenceSpecification();
		finishEOS.setName(
				createUniqueName(getNamespaceFragments(), "FinishEO_"));
		
		// Create Start ExecutionEvent
		startEvent = UMLFactory.eINSTANCE.createExecutionEvent();
		startEvent.setName(
				createUniqueName(
						coveredLifeline.getNearestPackage(),
						"StartExecEvt_"));

		// Create Start ExecutionEvent
		finishEvent = UMLFactory.eINSTANCE.createExecutionEvent();
		finishEvent.setName(
				createUniqueName(
						coveredLifeline.getNearestPackage(), 
						"FinishExecEvt_"));	
				
		// Set properties
		executionSpecification.setStart(startEOS);
		executionSpecification.setFinish(finishEOS);
		startEOS.setExecution(executionSpecification);
		finishEOS.setExecution(executionSpecification);
		startEOS.setEvent(startEvent);
		finishEOS.setEvent(finishEvent);
		startEOS.getCovereds().add(coveredLifeline);
		finishEOS.getCovereds().add(coveredLifeline);

		coveredLifeline.getNearestPackage().getPackagedElements().add(startEvent);
		coveredLifeline.getNearestPackage().getPackagedElements().add(finishEvent);
		
		Collection<InteractionFragment> collection = 
			new ArrayList<InteractionFragment>(3);
		collection.add(startEOS);
		collection.add(finishEOS);
		collection.add(executionSpecification);

		getNamespaceFragments().addAll(collection);
	}

	@Override
	public void undo() {
		startEOS = (ExecutionOccurrenceSpecification) executionSpecification
				.getStart();
		finishEOS = (ExecutionOccurrenceSpecification) executionSpecification
				.getFinish();

		Collection<InteractionFragment> collection = new ArrayList<InteractionFragment>(
				3);
		collection.add(executionSpecification);
		collection.add(startEOS);
		collection.add(finishEOS);

		getNamespaceFragments().removeAll(collection);

		coveredLifeline.getNearestPackage().getPackagedElements().remove(startEvent);
		coveredLifeline.getNearestPackage().getPackagedElements().remove(finishEvent);
		
		executionSpecification.setStart(null);
		executionSpecification.setFinish(null);
		executionSpecification.setName(null);

		startEOS.setExecution(null);
		finishEOS.setExecution(null);
		
		startEOS.setEvent(null);
		finishEOS.setEvent(null);
	}

	@Override
	public void redo() {

		// Create BehaviorExecutionSpecification
		executionSpecification = 
			UMLFactory.eINSTANCE.createBehaviorExecutionSpecification();
		executionSpecification.setName(
				createUniqueName(getNamespaceFragments(), "ExecSpec_"));

		// Create Start ExecutionOccurenceSpecification
		startEOS = UMLFactory.eINSTANCE.createExecutionOccurrenceSpecification();
		startEOS.setName(
				createUniqueName(getNamespaceFragments(), "StartEO_"));

		// Create Stop ExecutionOccurenceSpecification
		finishEOS = UMLFactory.eINSTANCE.createExecutionOccurrenceSpecification();
		finishEOS.setName(
				createUniqueName(getNamespaceFragments(), "FinishEO_"));

		// Set properties
		executionSpecification.setStart(startEOS);
		executionSpecification.setFinish(finishEOS);
		startEOS.setExecution(executionSpecification);
		finishEOS.setExecution(executionSpecification);
		startEOS.setEvent(startEvent);
		finishEOS.setEvent(finishEvent);
		startEOS.getCovereds().add(coveredLifeline);
		finishEOS.getCovereds().add(coveredLifeline);
		
		coveredLifeline.getNearestPackage().getPackagedElements().add(startEvent);
		coveredLifeline.getNearestPackage().getPackagedElements().add(finishEvent);
		
		Collection<InteractionFragment> collection = 
			new ArrayList<InteractionFragment>(3);
		collection.add(startEOS);
		collection.add(finishEOS);
		collection.add(executionSpecification);

		getNamespaceFragments().addAll(collection);
	}

	@Override
	public void dispose() {
		executionSpecification = null;
		super.dispose();
	}
	
	protected abstract ExecutionSpecification CreateExecutionSpecificationElement();
}
